﻿using Ewk.Math.Algebra.Algorithms.Matrices.Rank;
using Ewk.Math.Algebra.UnitTests.MatrixTests;
using Ewk.Math.ComputationTypes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Ewk.Math.Algebra.UnitTests.Algorithms.Matrices
{
    [TestClass]
    public class GaussianEliminationTests : MatrixUnitTestsBase<double>
    {
        GaussianElimination<double> _computer;

        protected override void AdditionalSetup()
        {
            base.AdditionalSetup();

            _computer = new GaussianElimination<double>();
        }

        [TestMethod]
        public void GaussianElimination_ComputeRank_returns_zero_when_the_matrix_is_null()
        {
            var rank = _computer.ComputeRank(null);

            Assert.AreEqual(0, rank);
        }

        [TestMethod]
        public void GaussianElimination_ComputeRank_tries_to_compute_the_rank_of_a_matrix()
        {
            /* Matrix 1
                    1   2   3   4 
                    --------------
                1 | 0   0   0   1 
                2 | 0   0   1   2 
                3 | 0   1   2   3
                4 | 1   2   3   4
                5 | 2   3   4   5
                6 | 3   4   5   6
                7 | 4   5   6   7
                8 | 5   6   7   8
            */

            const int rowCount = 8;
            const int columnCount = 4;
            var matrix1 = CreateMatrix(rowCount, columnCount, (i, j) => System.Math.Max(0, i + j - columnCount + 2));

            DeterminantManipulator
                .Expect(manipulations => manipulations.SwapColumns(Arg<int>.Is.Anything, Arg<int>.Is.Anything))
                .Return(Computable<double>.Factory.One);
            DeterminantManipulator.Replay();

            var rank = _computer.ComputeRank(matrix1);
            Assert.AreEqual(2, rank);
        }

        [TestMethod]
        public void GaussianElimination_ComputeRank_computes_the_rank_of_a_matrix1()
        {
            /* Matrix 1
                    1   2   3
                    ---------
                1 | 3   0   2
                2 | 1  -1   3
                3 |-1   2   4
            */

            var matrix1 = CreateMatrix(new double[,]
                                           {
                                               {3, 0, 2},
                                               {1, -1, 3},
                                               {-1, 2, 4}
                                           });

            var rank = _computer.ComputeRank(matrix1);
            Assert.AreEqual(3, rank);
        }

        [TestMethod]
        public void GaussianElimination_ComputeRank_computes_the_rank_of_a_matrix2()
        {
            /* Matrix 1
                    1   2   3
                    ---------
                1 | 2   2   3
                2 | 1   3   2
                3 | 1   1   2
            */

            var matrix1 = CreateMatrix(new double[,]
                                           {
                                               {2, 2, 3},
                                               {1, 3, 2},
                                               {1, 1, 2}
                                           });

            var rank = _computer.ComputeRank(matrix1);
            Assert.AreEqual(3, rank);
        }
    }
}
